#ifndef XLCOMM_NET_EVENTLOOP_H_
#define XLCOMM_NET_EVENTLOOP_H_

#include <memory>
#include <mutex>
#include <vector>

#include "xlcomm/base/condition_latch.h"
#include "xlcomm/base/current_thread.h"
#include "xlcomm/base/date_time.h"
#include "xlcomm/define.h"
#include "xlcomm/net/callbacks.h"
#include "xlcomm/net/timer_id.h"
#include "xlcomm/noncopyable.h"

namespace xlcomm {
namespace net {

class Poller;
class Channel;
class TimerQueue;

// IO事件循环处理（one loop per thread）线程安全
// EventLoop、Poller、Channel构成了Reactor模式的核心
class XLCOMM_API EventLoop : noncopyable {
 public:
  using Functor = std::function<void()>;

  // 每个线程只能拥有一个EventLoop对象
  EventLoop();
  ~EventLoop();

  // 运行事件循环，阻塞监听IO事件（必须在创建此对象的IO线程调用）
  void Loop();
  // 退出事件循环（调用者需保证对象还没被析构）
  void Quit();

  // 更新Channel监听的IO事件(内部Poller处理)
  void UpdateChannel(Channel* channel);
  // 移除Channel监听的IO事件
  void RemoveChannel(Channel* channel);
  // 检查是否持有某个Channel
  bool HasChannel(Channel* channel) const;

  // 如果在当前IO线程调用，回调会同步运行；如果在其他线程调用，将回调加入队列异步运行
  void RunInLoop(Functor func);
  // 将回调函数加入队列异步运行
  void QueueInLoop(Functor func);

  // 在某个时间点运行函数
  TimerId RunAt(Timestamp time, TimerCallback cb);
  // 在多少秒之后运行函数
  TimerId RunAfter(double delay_second, TimerCallback cb);
  // 每隔多少秒运行一次函数
  TimerId RunEvery(double interval_second, TimerCallback cb);
  // TODO: 取消定时任务
  void Cancel(TimerId timerId) {}

  // 每个EventLoop对象只能由一个IO线程操作
  // 该函数用于检查是否在该IO线程运行
  bool IsInLoopThread() const {
    return CurrentThread::GetThreadId() == creator_thread_id_;
  }

  Timestamp poll_return_time() const { return poll_return_time_; }
  int64_t poll_count() const { return poll_count_; }

  // 获取当前线程创建的EventLoop对象指针，如果没有则返回nullptr
  static EventLoop* GetEventLoopOfCurrentThread();

 private:
  using ChannelList = std::vector<Channel*>;

  // 不是在该IO线程运行，输出错误信息并中断程序
  void AbortNotInLoopThread() const;
  // 唤醒监听线程
  void Wakeup();
  // 处理wakeup_fd_可读事件
  void HandleRead();
  // 运行待处理函数
  void DoPendingFunctors();
  // 打印活动的Channels
  void PrintActiveChannels() const;

  uint64_t creator_thread_id_;
  bool looping_;
  bool calling_pending_functors_;
  int64_t poll_count_;
  ConditionLatch stop_latch_;
  Timestamp poll_return_time_;
  std::unique_ptr<Poller> poller_;
  std::unique_ptr<TimerQueue> timer_queue_;
  int wakeup_fd_;
  std::unique_ptr<Channel> wakeup_channel_;
  ChannelList active_channels_;
  std::mutex functor_mutex_;
  std::vector<Functor> pending_functors_;
};

}  // namespace net
}  // namespace xlcomm

#endif  // XLCOMM_NET_EVENTLOOP_H_